/*
插件通过vue.use()注册, vue.use实际是调用参数中传入的对象的install方法
* 实现思路:
* 1. vueRouter内部需要静态方法install
* 1.1 判断插件是否已经被加载
* 1.2 当Vue加载的时候把传入的router对象挂载到Vue实例上, 即new Vue时传入的router(注意: 只执行一次挂载操作)
* 2. VueRouter类实现
* 2.1 初始化, options, routeMap, app
* 2.2 initRouteMap()遍历所有路由信息, 把组件和路由的映射记录到routeMap对象中
* 2.3 注册popstate事件, 当路由地址发生变化, 重新记录当前的路径
* 2.4 创建router - link和router - view组件
* 2.5 当路径改变的时候通过当前路径在routerMap对象中找到对应的组件, 渲染router - view
*/
let _Vue = null;
export default class VueRouter {
  static install (Vue){
    // 1、判断当前节点是否已经被安装了
    if(VueRouter.install.installed){
      return
    }
    VueRouter.install.installed = true
    // 2、把VUe构造函数记录到全局变量
    _Vue = Vue
    // 3、把创建Vue实例时候传入的router对象注入到Vue实例上
    // _Vue.prototype.$router = this.$options.router

    //混入
    _Vue.mixin({
      beforecreate () {
        if (this.$options.router){
          _Vue.prototype.$router = this.$options.router
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    this.options = options
    this.routeMap = {}
    this.data = _Vue.observable({
      current: '/'
    })
  }

  init (){
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  createRouteMap () {
    // 遍历所有的路有规则，把路由规则解析为键值对形式，存储到routerMap对象中
    this.options.routes.forEach(route =>{
      this.routeMap[route.path] = route.component
    })
  }

  initComponents (Vue) {
    Vue.component('router-link', {
      props:{
        to:String
      },
      // template:'<a :href = "to><slot><slot></a>'
      // 使用运行时版本的Vue.js
      render (h) {
        return h('a',{
          attrs:{
            href: this.to
          },
          on: {
            click: this.clickHandler
          }
          // 使用运行时版本的Vue.js
        },[this.$slot.default])
      },
      methods:{
        clickHandler (e){
          history.pushState({}, '', this.to)
          this.$router.data.current = this.to
          e.preventDefault()
        }
      }
    })
    const self = this
    Vue.component('router-view', {
      render(h) {
        const component = self.routeMap[self.data.current]
        return h(component)
      }
    })
  }

  initEvent () {
    // window.addEventListener('popstate',() => {
    //   this.data.current = window.location.pathname
    // })
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    window.addEventListener('load', this.onHashChange.bind(this))
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname;
    })
  }
  onHashChange() {
    this.app.current = window.location.hash.substr(1) || '/'
  }
}